package wslib

import (
	"errors"
	"fmt"
	"log"
	"sync"

	"github.com/gorilla/websocket"
)

// session事件回调
type SessionHandler interface {
	// 会话建立
	WSSessionCreated(session *WsSession) bool
	// 会话断开
	WSSessionClosed(session *WsSession)
	// 会话数据
	WSSessionReceived(session *WsSession, tp int, data []byte) bool
}

// websocket会话
type WsSession struct {
	conn    *websocket.Conn // ws连接
	handler SessionHandler  // 回调
	wait    sync.WaitGroup  // 等待
}

// 新建会话，调用会话建立事件回调
func WsSessionStart(conn *websocket.Conn, handler SessionHandler) *WsSession {
	session := &WsSession{conn: conn, handler: handler}
	if handler.WSSessionCreated(session) {
		session.wait.Add(1)
		go func() {
			defer session.wait.Done()
			session.service()
		}()
		return session
	}
	return nil
}

// 返回会话网络连接
func (w *WsSession) Conn() *websocket.Conn {
	return w.conn
}

// 发送数据
func (w *WsSession) Write(messageType int, data []byte) error {
	if w.conn == nil {
		return errors.New("WsSession no connection")
	}
	err := w.conn.WriteMessage(messageType, data)
	if err != nil {
		log.Println("WsSession write err:", err)
	}
	return err
}

// 关闭会话，关闭网络连接，会话服务自动退出
func (w *WsSession) Stop() {
	// 关闭连接
	w.conn.Close()
	// 等待服务退出
	w.wait.Wait()
}

// 服务
func (w *WsSession) service() {
	defer func() {
		w.handler.WSSessionClosed(w)
		w.conn.Close()
		w.conn = nil
		fmt.Println("#exit exit WsSession Service")
	}()
	for {
		mt, message, err := w.conn.ReadMessage()
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
				log.Println("WsSession read err:", err)
				return
			}
		}
		// log.Printf("WsSession recv: %s: %d: %s", w.conn.RemoteAddr().String(), mt, message)
		if mt == -1 || len(message) == 0 {
			// closed
			return
		}
		if !w.handler.WSSessionReceived(w, mt, message) {
			return
		}
	}
}
